﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Collections;
using System.Text.RegularExpressions;
using System.Net;
using System.Threading;

namespace MasterAPI
{
    public class GameServerConnThread
    {
        private ArrayList clientSocketsRef;
        private int threads;
        private ArrayList dataLines;
        private Socket handler; //Client
        private Socket listener; //Server
        private bool Alive;
        private int clientIndex;
        private string typeString = "NaN";
        private byte[] bytes = new byte[1024];
        public string data;
        public IPEndPoint clientEndPoint;
        private bool identified = false;
        private int disconnectamm = 0;
        private bool disDone = false;
        public GameServerConnThread(Socket clientSocket, Socket serverListener, int threadsCount, ArrayList dataLinesRef, ArrayList clientSockets, byte[] srv_password)
        {
            this.handler = clientSocket;
            this.listener = serverListener;
            this.threads = threadsCount;
            this.clientSocketsRef = clientSockets;
            this.dataLines = dataLinesRef;
            this.Alive = true;
        }
        public void main()
        {
            this.clientIndex = this.clientSocketsRef.Count;
            Console.WriteLine("[" + typeString + "][" + clientIndex + "]" + "Connected!");
            while (true)
            {
                //Create Byte
                bytes = new byte[1024];
                //Create Byte Received Variable.
                int bytesRec = 0;
                try
                {
                    //Wait until Bytes are Sent from client. Then set Bytes to bytes variable.
                    bytesRec = handler.Receive(bytes);
                }
                catch (Exception e)
                {
                    //Write Error (if any).
                }
                //Convert Bytes to String.
                data += Encoding.ASCII.GetString(bytes, 0, bytesRec);

                string[] splitData = Regex.Split(data, "\n");
                #region ParseLine
                foreach (string line in splitData)
                {
                    string[] splitCommand = Regex.Split(line, "->");
                    try
                    {
                        if (line != "")
                        {
                            switch (splitCommand[0])
                            {
                                case "MasterServer":
                                    switch (splitCommand[1])
                                    {
                                        case "Heartbeat":
                                            switch (splitCommand[2])
                                            {
                                                case "Send":
                                                    MasterAPI.MasterServerConn.availableClients -= 1;
                                                    handler.Send(Encoding.ASCII.GetBytes("MasterServer->Heartbeat->Verify->Beat"));
                                                    MasterAPI.MasterServerConn.availableClients += 1;
                                                    Console.Title = "Todesesser Master Server - Online Clients: " + MasterAPI.MasterServerConn.activeClients + ", Available Servers: " + MasterAPI.MasterServerConn.availableClients;
                                                    break;
                                            }
                                            break;
                                        case "List":
                                            switch (splitCommand[2])
                                            {
                                                case "SendEndPoint":
                                                    string[] splitEndPoint = Regex.Split(splitCommand[3], ":");
                                                    clientEndPoint = new IPEndPoint(IPAddress.Parse(splitEndPoint[0]), int.Parse(splitEndPoint[1]));
                                                    break;
                                                case "SendAddress":
                                                    if (MasterAPI.MasterServerConn.gameServers.ContainsKey(clientEndPoint) == false)
                                                    {
                                                        MasterAPI.MasterServerConn.gameServers.Add(clientEndPoint, new GameServerObject());
                                                        MasterAPI.MasterServerConn.gameServers[clientEndPoint].Address = splitCommand[3];
                                                        if (identified == false)
                                                        {
                                                            MasterAPI.MasterServerConn.availableClients += 1;
                                                        }
                                                    }
                                                    else
                                                    {
                                                        MasterAPI.MasterServerConn.gameServers[clientEndPoint].Address = splitCommand[3];
                                                    }
                                                    break;
                                                case "SendPort":
                                                    if (MasterAPI.MasterServerConn.gameServers.ContainsKey(clientEndPoint) == false)
                                                    {
                                                        MasterAPI.MasterServerConn.gameServers.Add(clientEndPoint, new GameServerObject());
                                                        MasterAPI.MasterServerConn.gameServers[clientEndPoint].Port = splitCommand[3];
                                                    }
                                                    else
                                                    {
                                                        MasterAPI.MasterServerConn.gameServers[clientEndPoint].Port = splitCommand[3];
                                                    }
                                                    break;
                                                case "SendLocation":
                                                    if (MasterAPI.MasterServerConn.gameServers.ContainsKey(clientEndPoint) == false)
                                                    {
                                                        MasterAPI.MasterServerConn.gameServers.Add(clientEndPoint, new GameServerObject());
                                                        MasterAPI.MasterServerConn.gameServers[clientEndPoint].Location = splitCommand[3];
                                                    }
                                                    else
                                                    {
                                                        MasterAPI.MasterServerConn.gameServers[clientEndPoint].Location = splitCommand[3];
                                                    }
                                                    break;
                                                case "SendCurrentPlayers":
                                                    if (MasterAPI.MasterServerConn.gameServers.ContainsKey(clientEndPoint) == false)
                                                    {
                                                        MasterAPI.MasterServerConn.gameServers.Add(clientEndPoint, new GameServerObject());
                                                        MasterAPI.MasterServerConn.gameServers[clientEndPoint].CurrentPlayers = splitCommand[3];
                                                    }
                                                    else
                                                    {
                                                        MasterAPI.MasterServerConn.gameServers[clientEndPoint].CurrentPlayers = splitCommand[3];
                                                    }
                                                    Console.WriteLine(splitCommand[3]);
                                                    Console.WriteLine(clientEndPoint.ToString());
                                                    break;
                                                case "SendMaxPlayers":
                                                    if (MasterAPI.MasterServerConn.gameServers.ContainsKey(clientEndPoint) == false)
                                                    {
                                                        MasterAPI.MasterServerConn.gameServers.Add(clientEndPoint, new GameServerObject());
                                                        MasterAPI.MasterServerConn.gameServers[clientEndPoint].MaxPlayers = splitCommand[3];
                                                    }
                                                    else
                                                    {
                                                        MasterAPI.MasterServerConn.gameServers[clientEndPoint].MaxPlayers = splitCommand[3];
                                                    }
                                                    break;
                                                case "SendType":
                                                    if (MasterAPI.MasterServerConn.gameServers.ContainsKey(clientEndPoint) == false)
                                                    {
                                                        MasterAPI.MasterServerConn.gameServers.Add(clientEndPoint, new GameServerObject());
                                                        MasterAPI.MasterServerConn.gameServers[clientEndPoint].Type = splitCommand[3];
                                                    }
                                                    else
                                                    {
                                                        MasterAPI.MasterServerConn.gameServers[clientEndPoint].Type = splitCommand[3];
                                                    }
                                                    break;
                                                case "SendOptional":
                                                    if (MasterAPI.MasterServerConn.gameServers.ContainsKey(clientEndPoint) == false)
                                                    {
                                                        MasterAPI.MasterServerConn.gameServers.Add(clientEndPoint, new GameServerObject());
                                                        MasterAPI.MasterServerConn.gameServers[clientEndPoint].Optional = splitCommand[3];
                                                    }
                                                    else
                                                    {
                                                        MasterAPI.MasterServerConn.gameServers[clientEndPoint].Optional = splitCommand[3];
                                                    }
                                                    break;
                                                case "SendOwner":
                                                    if (MasterAPI.MasterServerConn.gameServers.ContainsKey(clientEndPoint) == false)
                                                    {
                                                        MasterAPI.MasterServerConn.gameServers.Add(clientEndPoint, new GameServerObject());
                                                        MasterAPI.MasterServerConn.gameServers[clientEndPoint].Owner = splitCommand[3];
                                                    }
                                                    else
                                                    {
                                                        MasterAPI.MasterServerConn.gameServers[clientEndPoint].Owner = splitCommand[3];
                                                    }
                                                    break;
                                                case "GetCount":
                                                    handler.Send(Encoding.ASCII.GetBytes(MasterAPI.MasterServerConn.gameServers.Count.ToString() + "\n"));
                                                    break;
                                                case "ReceiveAll":
                                                    string tosend = "";
                                                    foreach (KeyValuePair<IPEndPoint, GameServerObject> gameServer in MasterAPI.MasterServerConn.gameServers)
                                                    {
                                                        tosend += gameServer.Value.Address + ":" + 
                                                            gameServer.Value.Port + ":" + 
                                                            gameServer.Value.Location + ":" + 
                                                            gameServer.Value.CurrentPlayers + ":" + 
                                                            gameServer.Value.MaxPlayers + ":" + 
                                                            gameServer.Value.Type + ":" + 
                                                            gameServer.Value.Optional + ":" + 
                                                            gameServer.Value.Owner + "\n";
                                                        Console.WriteLine(tosend);
                                                    }
                                                    handler.Send(Encoding.ASCII.GetBytes(tosend));
                                                    break;
                                                case "ReceiveIndex":
                                                    break;
                                            }
                                            break;
                                    }
                                    break;
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        SpecialConsole.Text.WriteLine("Invalid Command Received: " + line + " @ ERROR: " + e.Message, ConsoleColor.Yellow);
                    }
                }
                #endregion
                //Reset
                data = "";
                //Check if Client Alive?
                if (SocketExtensions.IsConnected(handler) == false)
                {
                    try
                    {
                        //Client Not Connected lets Remove it.
                        disconnectamm += 1;
                        Console.Title = "Todesesser Master Server - Online Clients: " + MasterAPI.MasterServerConn.activeClients + ", Available Servers: " + MasterAPI.MasterServerConn.availableClients;
                        if (disDone == false)
                        {
                            Console.WriteLine("[" + typeString + "][" + clientIndex + "]" + "Disconnected!");
                            disDone = true;
                        }
                        Alive = false;
                        Thread currThread = (Thread)MasterAPI.MasterServerConn.clientThreads[clientIndex - 1];
                        currThread.Abort();
                        MasterAPI.MasterServerConn.clientSockets.Remove(this.handler);
                        int activeClients = 0;
                        foreach (Socket sock in clientSocketsRef)
                        {
                            if (sock != null)
                            {
                                activeClients += 1;
                            }
                        }
                        MasterAPI.MasterServerConn.activeClients = activeClients;
                    }
                    catch (Exception e)
                    {

                    }
                }
                //Check if there are problems removing threads
                if (disconnectamm >= 10)
                {
                    try
                    {
                        foreach (Thread gsThread in MasterAPI.MasterServerConn.clientThreads)
                        {
                            gsThread.Abort();
                            disconnectamm = 0;
                            MasterAPI.MasterServerConn.activeClients = 0;
                        }
                    }
                    catch (Exception e)
                    {

                    }
                }
            }
        }
    }
}
/// <summary>
/// Some Extensions for Sockets.
/// </summary>
public static class SocketExtensions
{
    public static bool IsConnected(this Socket socket)
    {
        try
        {
            return !(socket.Poll(1, SelectMode.SelectRead) && socket.Available == 0);
        }
        catch (SocketException) { return false; }
    }
}
